/*
 * This software is subject to the terms of the Eclipse Public License v1.0
 * Agreement, available at the following URL:
 * http://www.eclipse.org/legal/epl-v10.html.
 * You must accept the terms of that agreement to use this software.
 *
 * Copyright (C) 2022 Sergei Semenkov
 * Copyright (C) 2002-2024 Hitachi Vantara
 * All rights reserved.
 */

package mondrian.olap4j;

import mondrian.olap.OlapElement;
import org.olap4j.OlapException;
import org.olap4j.impl.AbstractNamedList;
import org.olap4j.impl.Named;
import org.olap4j.impl.NamedListImpl;
import org.olap4j.impl.Olap4jUtil;
import org.olap4j.metadata.Dimension;
import org.olap4j.metadata.Hierarchy;
import org.olap4j.metadata.Level;
import org.olap4j.metadata.Member;
import org.olap4j.metadata.NamedList;

import java.util.List;

/**
 * Implementation of {@link org.olap4j.metadata.Hierarchy}
 * for the Mondrian OLAP engine.
 *
 * @author jhyde
 * @since May 25, 2007
 */
public class MondrianOlap4jHierarchy extends MondrianOlap4jMetadataElement implements Hierarchy, Named {
  final MondrianOlap4jSchema olap4jSchema;
  final mondrian.olap.Hierarchy hierarchy;

  MondrianOlap4jHierarchy( MondrianOlap4jSchema olap4jSchema, mondrian.olap.Hierarchy hierarchy ) {
    this.olap4jSchema = olap4jSchema;
    this.hierarchy = hierarchy;
  }

  public boolean equals( Object obj ) {
    return obj instanceof MondrianOlap4jHierarchy && hierarchy.equals( ( (MondrianOlap4jHierarchy) obj ).hierarchy );
  }

  public int hashCode() {
    return hierarchy.hashCode();
  }

  public Dimension getDimension() {
    return new MondrianOlap4jDimension( olap4jSchema, hierarchy.getDimension() );
  }

  public NamedList<Level> getLevels() {
    final NamedList<MondrianOlap4jLevel> list = new NamedListImpl<>();
    final MondrianOlap4jConnection olap4jConnection =
      olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
    final mondrian.olap.SchemaReader schemaReader =
      olap4jConnection.getMondrianConnection2().getSchemaReader().withLocus();

    for ( mondrian.olap.Level level : schemaReader.getHierarchyLevels( hierarchy ) ) {
      list.add( olap4jConnection.toOlap4j( level ) );
    }

    return Olap4jUtil.cast( list );
  }

  public boolean hasAll() {
    return hierarchy.hasAll();
  }

  public Member getDefaultMember() throws OlapException {
    final MondrianOlap4jConnection olap4jConnection =
      olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
    final mondrian.olap.SchemaReader schemaReader =
      olap4jConnection.getMondrianConnection().getSchemaReader().withLocus();

    return olap4jConnection.toOlap4j( schemaReader.getHierarchyDefaultMember( hierarchy ) );
  }

  public NamedList<Member> getRootMembers() throws OlapException {
    final MondrianOlap4jConnection olap4jConnection =
      olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;
    final List<mondrian.olap.Member> levelMembers =
      olap4jConnection.getMondrianConnection().getSchemaReader().withLocus()
        .getLevelMembers( hierarchy.getLevels()[ 0 ], true );

    return new AbstractNamedList<Member>() {
      public String getName( Object member ) {
        return ( (Member) member ).getName();
      }

      public Member get( int index ) {
        return olap4jConnection.toOlap4j( levelMembers.get( index ) );
      }

      public int size() {
        return levelMembers.size();
      }
    };
  }

  public String getName() {
    return hierarchy.getName();
  }

  public String getUniqueName() {
    return hierarchy.getUniqueName();
  }

  public String getCaption() {
    return hierarchy.getLocalized( OlapElement.LocalizedProperty.CAPTION, olap4jSchema.getLocale() );
  }

  public String getDescription() {
    return hierarchy.getLocalized( OlapElement.LocalizedProperty.DESCRIPTION, olap4jSchema.getLocale() );
  }

  public boolean isVisible() {
    return hierarchy.isVisible();
  }

  protected OlapElement getOlapElement() {
    return hierarchy;
  }

  public String getDisplayFolder() {
    return hierarchy.getDisplayFolder();
  }

  public mondrian.olap.Hierarchy getHierarchy() {
    return hierarchy;
  }
}
